#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/errno.h>
#include <linux/string.h>

#define HELLO_CHAR_MAJOR (300)
#define HELLO_CHAR_NAME "hello_char"

static ssize_t hello_char_read(struct file *file, char __user *user, size_t len, loff_t *loff)
{
    char buf[32] = "hello read";
    unsigned long ret;

    printk("[%s][%d]\r\n", __func__, __LINE__);

    if (len >= strlen(buf))
        len = strlen(buf);

    ret = copy_to_user(user, buf, len);
    if (ret == 0)
    {
        return len;
    }
    else
    {
        printk("[%s][%d] copy_to_user err, %lu\r\n", __func__, __LINE__, ret);
        return ret;
    }

    return 0;
}

static ssize_t hello_char_write(struct file *file, const char __user *user, size_t len, loff_t *loff)
{
    char buf[32] = {0};
    unsigned long ret;

    printk("[%s][%d]\r\n", __func__, __LINE__);

    if (len >= 32)
        return -EMSGSIZE;

    ret = copy_from_user(buf, user, len);
    if (ret == 0)
    {
        printk("[%s][%d] write ok, %d, %s\r\n", __func__, __LINE__, len, buf);
        return len;
    }
    else
    {
        printk("[%s][%d] write err, %lu\r\n", __func__, __LINE__, ret);
        return ret;
    }

    return 0;
}

static int hello_char_open(struct inode *inode, struct file *file)
{
    printk("[%s][%d]\r\n", __func__, __LINE__);

    return 0;
}
static int hello_char_release(struct inode *inode, struct file *file)
{
    printk("[%s][%d]\r\n", __func__, __LINE__);

    return 0;
}

static struct file_operations fops = {
    .owner = THIS_MODULE,
    .read = hello_char_read,
    .write = hello_char_write,
    .open = hello_char_open,
    .release = hello_char_release,
};

static int __init hello_char_init(void)
{
    int ret;

    printk("[%s][%d]\r\n", __func__, __LINE__);

    ret = register_chrdev(HELLO_CHAR_MAJOR, HELLO_CHAR_NAME, &fops);
    if (ret < 0)
        return ret;

    return 0;
}

static void __exit hello_char_exit(void)
{
    unregister_chrdev(HELLO_CHAR_MAJOR, HELLO_CHAR_NAME);

    printk("[%s][%d]\r\n", __func__, __LINE__);
}

module_init(hello_char_init);

module_exit(hello_char_exit);

MODULE_AUTHOR("ljq");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("test char driver");
